package org.ethan.lyl;

import br.com.objectos.core.lang.Preconditions;
import com.alibaba.fastjson.JSON;
import org.ethan.lyl.util.StaticParams;
import org.ethan.lyl.util.StaticStatus;

import javax.imageio.ImageIO;
import java.awt.color.ColorSpace;
import java.awt.image.BufferedImage;
import java.awt.image.ColorConvertOp;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;

/**
 * @Author Ethan Lau
 * @CreateTime 2018/10/29 16:01
 * @Desc 根据图片分析出数组
 */
public final class ImgAnalysis {

    public static Coordinate[][] getArray(String path){
        try{
            //图片源文件
            BufferedImage bufferedImage = ImageIO.read(new FileInputStream(path));
            //二值化
            BufferedImage binaryImage = binaryImage(bufferedImage);
            //灰化
            //BufferedImage grayImage = getGrayImage(bufferedImage);

            //开始及结束坐标
            //System.out.println("获取模糊起始结束坐标");
            Coordinate vagueStart = getStartCoordinate(bufferedImage,"ffccc",20,bufferedImage.getHeight()-400,20,bufferedImage.getWidth()-20);
            Coordinate vagueEnd = getEndCoordinate(bufferedImage,"ffccc",20,bufferedImage.getHeight()-400,20,bufferedImage.getWidth()-20);
            //System.out.println("模糊开始坐标：" + JSON.toJSONString(vagueStart));
            //System.out.println("模糊结束坐标：" + JSON.toJSONString(vagueEnd));
            //System.out.println("获取精确起始结束坐标");
            Coordinate start = getStartCoordinate(binaryImage,"fffff",vagueStart.Y-10,vagueEnd.Y+10,vagueStart.X-10,vagueEnd.X+10);
            Coordinate end = getEndCoordinate(binaryImage,"fffff",vagueStart.Y-10,vagueEnd.Y+10,vagueStart.X-10,vagueEnd.X+10);
            //方块边长
            int itemWidth = getItemWidth(binaryImage,start,end);
            //内容长高
            int contentHeight = end.Y-start.Y;
            int contentWidth = end.X-start.X;
            //间隙宽度
            int rangeWidth = getRangeWidth(binaryImage,start,itemWidth);
            //横方块个数
            int itemWidthNum = (contentWidth+rangeWidth)/(itemWidth+rangeWidth);
            //纵方块个数
            int itemHeightNum = (contentHeight+rangeWidth)/(itemWidth+rangeWidth);

            System.out.println("开始坐标：" + JSON.toJSONString(start) +" 结束坐标：" + JSON.toJSONString(end));
            System.out.println("内容长高：" + contentWidth + " " + contentHeight);
            System.out.println("方块边长：" + itemWidth +" 间隙宽度：" + rangeWidth);
            System.out.println("横轴个数：" + itemWidthNum + " 纵轴个数：" + itemHeightNum);
            synchronized (StaticStatus.track) {
                StaticStatus.track.add(String.format("横轴个数:%d 纵轴个数%d", itemWidthNum,itemHeightNum));
            }

            //获取各方块属性
            Coordinate[][] coordinates = new Coordinate[itemHeightNum][itemWidthNum];
            for(int i=0;i<itemHeightNum;i++)//与Y有关
            {
                for (int j=0;j<itemWidthNum;j++){//与X有关
                    coordinates[i][j] = checkAndSetItem(
                            bufferedImage,
                            new Coordinate()
                                    .setX(start.getX()+(rangeWidth+itemWidth)*j)
                                    .setY(start.getY()+(rangeWidth+itemWidth)*i),
                            itemWidth);
                    //coordinates[i][j] = checkAndSetItem(bufferedImage,new Coordinate().setX(i==0?start.getX():start.getX()+(rangeWidth+itemWidth)*i).setY(j==0?start.getY():start.getY()+(rangeWidth+itemWidth)*j),itemWidth);
                }
            }
            //System.out.println(JSON.toJSONString(coordinates));
            System.out.println("二维数组：");
            for (int i=0;i<coordinates.length;i++){
                System.out.println("");
                for(int j=0;j<coordinates[i].length;j++){
                    System.out.print(String.format("%d\t",coordinates[i][j].getV()));
                }
            }
            System.out.println("");
            return coordinates;
        }catch (IOException e){
            e.printStackTrace();
            return null;
        }

    }

    /**
     * 将图片置灰 ---  使用现成的类
     * @param originalImage
     * @return
     */
    public static BufferedImage getGrayImage(BufferedImage originalImage) {
        BufferedImage grayImage;
        int imageWidth = originalImage.getWidth();
        int imageHeight = originalImage.getHeight();
        //TYPE_3BYTE_BGR -->  表示一个具有 8 位 RGB 颜色分量的图像，对应于 Windows 风格的 BGR 颜色模型，具有用 3 字节存储的 Blue、Green 和 Red 三种颜色。
        grayImage = new BufferedImage(imageWidth, imageHeight, BufferedImage.TYPE_3BYTE_BGR);
        ColorConvertOp cco = new ColorConvertOp(ColorSpace.getInstance(ColorSpace.CS_GRAY), null);
        cco.filter(originalImage, grayImage);
        return grayImage;
    }

    /*public static void main(String [] args){
        getData("E:\\OneDrive\\图片\\test2.jpg");
    }*/

    /**
     * 坐标
     */
    public static class Coordinate{
        public int X;
        public int Y;
        //int RGB;
        public int V;

        public int getV() {
            return V;
        }

        public Coordinate setV(int v) {
            V = v;
            return this;
        }

        public int getX() {
            return X;
        }

        public Coordinate setX(int x) {
            X = x;
            return this;
        }

        public int getY() {
            return Y;
        }

        public Coordinate setY(int y) {
            Y = y;
            return this;
        }

        /*public int getRGB() {
            return RGB;
        }

        public Coordinate setRGB(int RGB) {
            this.RGB = RGB;
            return this;
        }*/
    }

    /**
     * 获取小块的边长
     * @param img
     * @param start
     * @param end
     * @return
     */
    public static int getItemWidth(BufferedImage img, Coordinate start,Coordinate end){
        int width = 0;
        int cuRGB = 0;
        boolean isBreak = false;
        //自顶向下扫描
        for(int y=start.Y-20;y<end.Y+20;y++){
            for(int x=0;x<img.getWidth();x++){
                if(cuRGB!=0&&Integer.toHexString(img.getRGB(x,y)).indexOf("fff")!=0){
                    break;
                }
                else if("fff".equals(Integer.toHexString(img.getRGB(x,y)))||Integer.toHexString(img.getRGB(x,y)).indexOf("fff")==0){
                    cuRGB = img.getRGB(x,y);
                    isBreak = true;
                    width++;
                    continue;
                }
            }
            if(isBreak){
                break;
            }
        }
        return width;
    }

    /**
     * 获取起点
     * @param grayImage
     * @return
     */
    public static Coordinate getStartCoordinate(BufferedImage grayImage,String color,int startHeight,int endHeight,int startWidth,int endWidth){
        //String color = "ffcccc";
        int xx=0,yy=0;
        //获得xx;
        //自顶向下
        for(int y=startHeight;y<endHeight;y++){
            //自左向右
            for(int x=startWidth;x<endWidth;x++){
                if(Integer.toHexString(grayImage.getRGB(x,y)).indexOf(color)==0){
                    if(CheckBroColorIsSame.check(grayImage,color,x,y,CheckBroColorIsSame.RIGHT)){
                        yy = y;
                        break;
                    }

                }
            }
            if(yy!=0)
                break;
        }
        //获得yy
        //自左向右
        for(int x=startWidth;x<endWidth;x++){
            //自顶向下
            for(int y=startHeight;y<endHeight;y++){
                if(Integer.toHexString(grayImage.getRGB(x,y)).indexOf(color)==0){
                    if(CheckBroColorIsSame.check(grayImage,color,x,y,CheckBroColorIsSame.DOWN)){
                        xx = x;
                        break;
                    }

                }
            }
            if(xx!=0)
                break;
        }
        return new Coordinate().setX(xx).setY(yy);
    }

    /**
     * 获取终点
     * @param grayImage
     * @return
     */
    public static Coordinate getEndCoordinate(BufferedImage grayImage,String color,int startHeight,int endHeight,int startWidth,int endWidth){
        //String color = "ffcccc";
        int xx=0,yy=0;
        //自底向上
        for(int y=endHeight;y>startHeight;y--){
            //自右往左
            for(int x=endWidth;x>startWidth;x--){
                if(Integer.toHexString(grayImage.getRGB(x,y)).indexOf(color)==0){
                    if(CheckBroColorIsSame.check(grayImage,color,x,y,CheckBroColorIsSame.LEFT)){
                        yy = y;
                        break;
                    }

                }
            }
            if(yy!=0)
                break;
        }
        //自右向左
        for(int x=endWidth;x>=startWidth;x--){
            //自底向上
            for(int y=endHeight;y>startHeight;y--){
                if(Integer.toHexString(grayImage.getRGB(x,y)).indexOf(color)==0){
                    if(CheckBroColorIsSame.check(grayImage,color,x,y,CheckBroColorIsSame.UP)){
                        xx = x;
                        break;
                    }
                }
            }
            if(xx!=0)
                break;
        }
        return new Coordinate().setX(xx).setY(yy);
    }

    /**
     * 二值化
     * @throws IOException
     */
    public static BufferedImage binaryImage(BufferedImage image) throws IOException{

        int width = image.getWidth();
        int height = image.getHeight();

        BufferedImage binaryImage = new BufferedImage(width, height, BufferedImage.TYPE_BYTE_BINARY);//重点，技巧在这个参数BufferedImage.TYPE_BYTE_BINARY
        for(int i= 0 ; i < width ; i++){
            for(int j = 0 ; j < height; j++){
                int rgb = image.getRGB(i, j);
                binaryImage.setRGB(i, j, rgb);
            }
        }

        return binaryImage;
    }

    /**
     * 获取该方块属性
     * @param img 图片
     * @param start 开始坐标
     * @param itemWidth 方块宽度
     * @return
     */
    public static Coordinate checkAndSetItem(BufferedImage img,Coordinate start,int itemWidth){
        int grayPixelNum = 0,doesNotGrayPixelNum=0;//灰色像素点个数 非灰色像素点个数
        for(int p = StaticParams.getTrimming(); p<=itemWidth-StaticParams.getTrimming(); p++){
            if((Integer.toHexString(img.getRGB(start.getX()+p,start.getY()+p)).indexOf("ffcccc"))==0){
                grayPixelNum++;
            }
            else{
                doesNotGrayPixelNum++;
            }
        }
        if(doesNotGrayPixelNum==0){//标准方块
            return new Coordinate().setX((start.getX()+itemWidth/2)).setY((start.getY()+itemWidth/2)).setV(1);
        }
        else if(grayPixelNum==0){//空白
            return new Coordinate().setX((start.getX()+itemWidth/2)).setY((start.getY()+itemWidth/2)).setV(0);

        }
        else {//起点
            return new Coordinate().setX((start.getX()+itemWidth/2)).setY((start.getY()+itemWidth/2)).setV(2);
        }
    }

    /**
     * 计算方块之间的空隙长度
     * @param bufferedImage
     * @param start
     * @param itemWidth
     * @return
     */
    public static int getRangeWidth(BufferedImage bufferedImage, Coordinate start, int itemWidth){
        //FIXME 此代码是从左上角的点开始计算的，若左上角点不存在，则可能计算失败
        //先从左往右
        //获取下一点
        Coordinate next = new Coordinate().setX( start.X+itemWidth*2).setY(start.Y+10);
        if(Integer.toHexString(bufferedImage.getRGB(next.X,next.Y)).indexOf("fff")==0){//右点可用
            for(int w=1;w<=itemWidth;w++){
                if(Integer.toHexString(bufferedImage.getRGB(next.X+w,next.Y)).indexOf("fff")!=0){
                    return w-1;
                }
            }
        }
        else//往下
        {
            next = new Coordinate().setX(start.X+10).setY(start.Y + itemWidth*2);
            for(int w=1;w<=itemWidth;w++){
                if(Integer.toHexString(bufferedImage.getRGB(next.X,next.Y+w)).indexOf("fff")!=0){
                    return w-1;
                }
            }
        }
        return 0;

    }


    static class CheckBroColorIsSame{
        public static final int LEFT = 1;
        public static final int RIGHT = 2;
        public static final int UP = 3;
        public static final int DOWN = 4;

        /**
         * 检查该节点往某个方向上的30个节点是否颜色相同
         * @param bufferedImage
         * @param color
         * @param x
         * @param y
         * @param type
         * @return
         */
        public static boolean check(BufferedImage bufferedImage,String color,int x,int y,int type){
            switch (type){
                case LEFT:{
                    for(int i=1;i<=30;i++){
                        if(Integer.toHexString(bufferedImage.getRGB(x-i,y)).indexOf(color)==-1){
                            return false;
                        }
                    }
                    break;
                }
                case RIGHT:{
                    for(int i=1;i<=30;i++){
                        if(Integer.toHexString(bufferedImage.getRGB(x+i,y)).indexOf(color)==-1){
                            return false;
                        }
                    }
                    break;
                }
                case UP:{
                    for(int i=1;i<=30;i++){
                        if(Integer.toHexString(bufferedImage.getRGB(x,y-i)).indexOf(color)==-1){
                            return false;
                        }
                    }
                    break;
                }
                case DOWN:{
                    for(int i=1;i<=30;i++){
                        if(Integer.toHexString(bufferedImage.getRGB(x,y+i)).indexOf(color)==-1){
                            return false;
                        }
                    }
                    break;
                }
            }
            return true;
        }
    }


    /**
     * 获取下一关按钮坐标
     * @param binaryImg
     * @return
     */
    static public Coordinate getNextLevelCoodinate(BufferedImage binaryImg){
        Coordinate coordinate = null;
        for(int y=binaryImg.getHeight()-10;y>=0;y--){
            for (int x=0;x<binaryImg.getWidth()-10;x++){
                if(Integer.toHexString(binaryImg.getRGB(x,y)).indexOf("fffff")==0){
                    coordinate = new Coordinate().setX(x+20).setY(y-20);
                    break;
                }
            }
            if(coordinate!=null)
                break;
        }
        Preconditions.checkArgument(coordinate!=null,"获取下一关按钮坐标失败");
        return coordinate;
    }

    /**
     * 获取礼物关闭按钮坐标
     * @param binaryImg
     * @return
     */
    static public Coordinate getCloseGifeCoodinate(BufferedImage binaryImg){
        Coordinate coordinate = null;
        for (int x=binaryImg.getWidth()-10;x>0;x--){
            for(int y=binaryImg.getHeight()-10;y>200;y--){
                if(Integer.toHexString(binaryImg.getRGB(x,y)).indexOf("fffff")==0){
                    coordinate = new  Coordinate().setX(x-30).setY(y+30);
                    break;
                }
            }
            if(coordinate!=null)
                break;
        }
        Preconditions.checkArgument(coordinate!=null,"获取礼物关闭按钮坐标失败");
        return coordinate;
    }


}